package com.wzdigit.wms.basic.service.code;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wzdigit.framework.Shift;
import com.wzdigit.wms.basic.domain.basic.Location;
import com.wzdigit.wms.basic.domain.dtos.inventory.InventoryConditionDto;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inventory.InvLoc;
import com.wzdigit.wms.basic.domain.inventory.InvTrans;
import com.wzdigit.wms.basic.domain.transfer.InvZone;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.basic.util.common.CommonString;
import com.wzdigit.wms.basic.util.common.LockNumber;
import com.wzdigit.wms.basic.client.request.transfer.SearchInvRequest;
import com.wzdigit.wms.basic.client.response.transfer.InvQtyAndOutQtyResponse;
import com.wzdigit.wms.basic.mapper.core.basic.LocationMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.InvLocMapper;
import com.wzdigit.wms.basic.mapper.core.inventory.InvTransMapper;
import com.wzdigit.wms.basic.mapper.core.transfer.InvZoneMapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 库存服务
 */
@Service
@Slf4j
public class InventoryService {

    @Autowired
    private InvLocMapper invLocMapper;

    @Autowired
    private InvTransMapper invTransMapper;

    @Autowired
    private InvZoneMapper invZoneMapper;

    @Autowired
    private LocationMapper locationMapper;

    @Autowired
    private RedissonClient redisson;
    
    /**
     * 增加库存
     *
     * @param addInv
     * @param invTrans
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void inventoryIn(UpdateInventoryInputDto addInv, InvTrans invTrans) throws Exception {
        inventoryTransfer(null, addInv, invTrans);
    }

    /**
     * 减少库存
     *
     * @param subtractInv
     * @param invTrans
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void inventoryOut(UpdateInventoryInputDto subtractInv, InvTrans invTrans) throws Exception {
        inventoryTransfer(subtractInv, null, invTrans);
    }

    /**
     * 变更库存操作
     *
     * @param subtractInv	减少库存
     * @param addInv		增加库存
     * @param invTrans
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer inventoryTransfer(UpdateInventoryInputDto subtractInv, UpdateInventoryInputDto addInv, InvTrans invTrans) throws Exception {
        if (subtractInv != null) {
        	// 更新库位库存
            updateLocInventroy(subtractInv);
            // 更新库区库存
            updateZoneInventory(subtractInv);
            
            invTrans.setFmOwner(subtractInv.getOwner());
            invTrans.setFmSkuId(subtractInv.getSkuId());
            invTrans.setFmFactory(subtractInv.getFactory());
            invTrans.setFmLotno(subtractInv.getLotNo());
            invTrans.setFmVendorId(subtractInv.getVendorId());
            invTrans.setFmLocId(subtractInv.getLocId());
            invTrans.setFmWhsId(subtractInv.getWhsId());
            invTrans.setFmInvAttr(subtractInv.getInvAttr());
            invTrans.setFmQaStatus(subtractInv.getQaStatus());
            invTrans.setFmUnit(subtractInv.getUnit());
            
            invTrans.setFmQty(subtractInv.getQty());
            invTrans.setFmPreAlocQty(subtractInv.getPreAlocQty());
            invTrans.setFmPreInQty(subtractInv.getPreInQty());
            invTrans.setFmPreOutQty(subtractInv.getPreOutQty());
            invTrans.setFmHoldQty(subtractInv.getHoldQty());
            invTrans.setFmAlocQty(subtractInv.getAlocQty());

            invTrans.setCreateUser(subtractInv.getOperator());
        }
        if (addInv != null) {
        	// 更新库位库存
            updateLocInventroy(addInv);
            // 更新库区库存
            updateZoneInventory(addInv);
            
            invTrans.setToOwner(addInv.getOwner());
            invTrans.setToSkuId(addInv.getSkuId());
            invTrans.setToFactory(addInv.getFactory());
            invTrans.setToLotno(addInv.getLotNo());
            invTrans.setToVendorId(addInv.getVendorId());
            invTrans.setToLocId(addInv.getLocId());
            invTrans.setToWhsId(addInv.getWhsId());
            invTrans.setToInvAttr(addInv.getInvAttr());
            invTrans.setToQaStatus(addInv.getQaStatus());
            invTrans.setToUnit(addInv.getUnit());

            invTrans.setToQty(addInv.getQty());
            invTrans.setToPreAlocQty(addInv.getPreAlocQty());
            invTrans.setToPreInQty(addInv.getPreInQty());
            invTrans.setToPreOutQty(addInv.getPreOutQty());
            invTrans.setToHoldQty(addInv.getHoldQty());
            invTrans.setToAlocQty(addInv.getAlocQty());

            invTrans.setCreateUser(addInv.getOperator());
        }
        invTrans.setCreateTime(new Date());
        return insertInvTrans(invTrans);
    }

    /**
     * 更新库位库存
     * 
     * @param input
     * @return 
     * @return
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer updateLocInventroy(UpdateInventoryInputDto input) throws Exception {
    	// 仓库、库位、货主、物料、组织、供应商、批次号、库存性质、品质状态
    	String key = "Key_Inv_Loc_"
                + input.getWhsId() + "#loc" + input.getLocId() + "#" + input.getOwner() + "#"
                + input.getSkuId() + "#" + input.getFactory() + "#" + input.getVendorId() + "#"
                + input.getLotNo() + "#" + input.getInvAttr() + "#" + input.getQaStatus() + "#";
    	RLock lock = redisson.getLock(key);
        try {
        	// 加锁
        	long waitTime = LockNumber.SECONDS_I;	// 等待时间
        	long leaseTime = LockNumber.SECONDS_II;	// 过期时间
        	if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
        		if(StringUtils.isNull(input.getOperator())) {
        			// 默认用户名
        			input.setOperator(CommonString.DEFAULT_USER_NAME);
        		}
        		List<InvLoc> invLocList = getOrAddLocInvItem(input);
        		Integer invLocId = invLocList.get(0).getInvLocId();
        		// 库位库存检验
        		invQtyValidation(input, 0);
        		invLocMapper.updateQtyById(
        				invLocId,
        				input.getQty(),
        				input.getHoldQty(),
        				input.getAlocQty(),
        				input.getPreInQty(),
        				input.getPreOutQty(),
        				input.getPreAlocQty(),
        				input.getOperator());
        		return invLocId;
        	} else {
        		Shift.fatal("获取库存锁失败，库存更新失败！");
        	}
		} catch (Exception e) {
			throw e;
		} finally {
			// 当前线程获取到锁再释放锁
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
		}
        return null;
    }
    
    /**
     * 更新库区库存
     * 
     * @param input
     * @return 
     * @return
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer updateZoneInventory(UpdateInventoryInputDto input) throws Exception {
    	// 根据库位获取库区【库位不为空并且库区为空时触发】
    	if (input.getLocId() != null && input.getZoneId() == null) {
    		Location location = locationMapper.selectById(input.getLocId());
    		input.setZoneId(location.getZoneId());
    	}
    	
    	// 仓库、库区、货主、物料、组织、供应商、批次号、库存性质、品质状态
    	String key = "Key_Inv_Zone_"
    			+ input.getWhsId() + "#zone" + input.getZoneId() + "#" + input.getOwner() + "#"
    			+ input.getSkuId() + "#" + input.getFactory() + "#" + input.getVendorId() + "#"
    			+ input.getLotNo() + "#" + input.getInvAttr() + "#" + input.getQaStatus() + "#";
    	RLock lock = redisson.getLock(key);
        try {
        	// 加锁
        	long waitTime = LockNumber.SECONDS_I;	// 等待时间
        	long leaseTime = LockNumber.SECONDS_II;	// 过期时间
        	if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
        		if(StringUtils.isNull(input.getOperator())) {
        			// 默认用户名
        			input.setOperator(CommonString.DEFAULT_USER_NAME);
        		}
        		List<InvZone> invZoneList = getOrAddZoneItem(input);
        		Integer invZoneId = invZoneList.get(0).getInvZoneId();
        		// 库区库存检验
        		invQtyValidation(input, 1);
        		invZoneMapper.updateQtyById(
        				invZoneId,
        				input.getQty(),
        				input.getHoldQty(),
        				input.getAlocQty(),
        				input.getPreInQty(),
        				input.getPreOutQty(),
        				input.getPreAlocQty(),
        				input.getOperator());
        		return invZoneId;
        	} else {
        		Shift.fatal("获取库存锁失败，库存更新失败！");
        	}
		} catch (Exception e) {
			throw e;
		} finally {
			// 当前线程获取到锁再释放锁
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
		}
		return null;
    }
    
    /**
     * 校验库存
     * 
     * @param dto
     * @param dealType：0库位库存、1库区库存
     */
    public void invQtyValidation(UpdateInventoryInputDto dto, Integer dealType) {
        SearchInvRequest searchInvRequest = new SearchInvRequest();
        searchInvRequest.setWhsId(dto.getWhsId());
        searchInvRequest.setOwnerId(dto.getOwner());
        searchInvRequest.setSkuId(dto.getSkuId());
        searchInvRequest.setFactory(dto.getFactory());
        searchInvRequest.setVendorId(dto.getVendorId());
        searchInvRequest.setLotno(dto.getLotNo());
        searchInvRequest.setInvAttr(dto.getInvAttr());
        searchInvRequest.setQaStatus(dto.getQaStatus());
        searchInvRequest.setLocId(dto.getLocId());
        searchInvRequest.setZoneId(dto.getZoneId());
        
        // 数量
        BigDecimal qty = dto.getQty();
        // 支出数量（预支数量 + 冻结数量 + 分配数量）
        BigDecimal outQty = dto.getPreOutQty().add(dto.getHoldQty()).add(dto.getAlocQty());

        if(dealType == null) {
        	// 库位库存检验
    		List<InvQtyAndOutQtyResponse> qtyAndOutQty = invLocMapper.getQtyAndOutQty(searchInvRequest);
    		invQtyValidationDtl("库位", qty, outQty, qtyAndOutQty);
    		// 库区库存检验
    		qtyAndOutQty = invZoneMapper.getQtyAndOutQty(searchInvRequest);
    		invQtyValidationDtl("库区", qty, outQty, qtyAndOutQty);
        } else {
        	if(dealType == 0) {
        		// 库位库存检验
        		List<InvQtyAndOutQtyResponse> qtyAndOutQty = invLocMapper.getQtyAndOutQty(searchInvRequest);
        		invQtyValidationDtl("库位", qty, outQty, qtyAndOutQty);
        	} else {
        		// 库区库存检验
        		List<InvQtyAndOutQtyResponse> qtyAndOutQty = invZoneMapper.getQtyAndOutQty(searchInvRequest);
        		invQtyValidationDtl("库区", qty, outQty, qtyAndOutQty);
        	}
        }
    }
	private void invQtyValidationDtl(String text, BigDecimal qty, BigDecimal outQty,
			List<InvQtyAndOutQtyResponse> qtyAndOutQty) {
		log.info("{}库存校验【入参】：数量={};支出={}", text, qty, outQty);
		int i = 0;
		for (InvQtyAndOutQtyResponse one : qtyAndOutQty) {
			log.info("{}库存校验【现存{}】：数量={};支出={}", text, ++i, one.getQty(), one.getOutQty());
			qty = qty.add(one.getQty());
			outQty = outQty.add(one.getOutQty());
		}
		// 数量小于支出数量：可用库存变负数
		log.info("{}库存校验【结果】：数量={};支出={}", text, qty, outQty);
		if (qty.signum() == -1 || outQty.signum() == -1 || qty.compareTo(outQty) == -1) {
			Shift.fatal(text + "库存不足!");
		}
	}

    /**
     * 获取库位库存, 不存在则新增一行
     *
     * @param input
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public List<InvLoc> getOrAddLocInvItem(UpdateInventoryInputDto input) {
    	List<InvLoc> invLocList = getInvLocList(input);
        if (invLocList.size() == 0) {
        	if(input.getUnit() == null) {
        		Shift.fatal("库存单位不能为空!");
        	}
        	
            InvLoc item = new InvLoc();
            item.setLocId(input.getLocId());
            item.setWhsId(input.getWhsId());
            item.setOwner(input.getOwner());
            item.setSkuId(input.getSkuId());
            item.setFactory(input.getFactory());
            item.setVendorId(input.getVendorId());
            item.setLotno(input.getLotNo());
            item.setInvAttr(input.getInvAttr());
            item.setQaStatus(input.getQaStatus());

            item.setUnit(input.getUnit());

            item.setCreateTime(new Date());
            item.setCreateUser(input.getOperator());
            invLocMapper.insert(item);
            invLocList.add(item);
        }
        return invLocList;
    }

    /**
     * 获取库区库存, 不存在则新增一行
     *
     * @param input
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public List<InvZone> getOrAddZoneItem(UpdateInventoryInputDto input) {
    	List<InvZone> invZoneList = getInvZoneList(input);
        if (invZoneList.size() == 0) {
        	if(input.getUnit() == null) {
        		Shift.fatal("库存单位不能为空!");
        	}
        	
            InvZone item = new InvZone();
            item.setZoneId(input.getZoneId());
            item.setWhsId(input.getWhsId());
            item.setOwner(input.getOwner());
            item.setSkuId(input.getSkuId());
            item.setFactory(input.getFactory());
            item.setVendorId(input.getVendorId());
            item.setLotno(input.getLotNo());
            item.setInvAttr(input.getInvAttr());
            item.setQaStatus(input.getQaStatus());
            
            item.setUnit(input.getUnit());
            
            item.setCreateTime(new Date());
            item.setCreateUser(input.getOperator());
            invZoneMapper.insert(item);
            invZoneList.add(item);
        }
        return invZoneList;
    }
    
    /**
     * 获取库位库存行ID
     *
     * @param input
     * @return
     */
    private List<InvLoc> getInvLocList(UpdateInventoryInputDto input) {
        QueryWrapper<InvLoc> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull(input.getLocId() == null, "LOC_ID");
        queryWrapper.eq(!(input.getLocId() == null), "LOC_ID", input.getLocId());
        
        queryWrapper.isNull(input.getWhsId() == null, "WHS_ID");
        queryWrapper.eq(!(input.getWhsId() == null), "WHS_ID", input.getWhsId());
        
        queryWrapper.isNull(input.getOwner() == null, "OWNER");
        queryWrapper.eq(!(input.getOwner() == null), "OWNER", input.getOwner());
        
        queryWrapper.isNull(input.getSkuId() == null, "SKU_ID");
        queryWrapper.eq(!(input.getSkuId() == null), "SKU_ID", input.getSkuId());
        
        queryWrapper.isNull(input.getFactory() == null, "FACTORY");
        queryWrapper.eq(!(input.getFactory() == null), "FACTORY", input.getFactory());

        queryWrapper.isNull(input.getVendorId() == null, "VENDOR_ID");
        queryWrapper.eq(!(input.getVendorId() == null), "VENDOR_ID", input.getVendorId());

        queryWrapper.isNull(input.getLotNo() == null, "LOTNO");
        queryWrapper.eq(!(input.getLotNo() == null), "LOTNO", input.getLotNo());

        queryWrapper.isNull(input.getInvAttr() == null, "INV_ATTR");
        queryWrapper.eq(!(input.getInvAttr() == null), "INV_ATTR", input.getInvAttr());

        queryWrapper.isNull(input.getQaStatus() == null, "QA_STATUS");
        queryWrapper.eq(!(input.getQaStatus() == null), "QA_STATUS", input.getQaStatus());

        List<InvLoc> list = invLocMapper.selectList(queryWrapper);
        return list;
    }
    
    /**
     * 获取库区库存行ID
     *
     * @param input
     * @return
     */
    private List<InvZone> getInvZoneList(UpdateInventoryInputDto input) {
        QueryWrapper<InvZone> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull(input.getZoneId() == null, "ZONE_ID");
        queryWrapper.eq(!(input.getZoneId() == null), "ZONE_ID", input.getZoneId());
        
        queryWrapper.isNull(input.getWhsId() == null, "WHS_ID");
        queryWrapper.eq(!(input.getWhsId() == null), "WHS_ID", input.getWhsId());
        
        queryWrapper.isNull(input.getOwner() == null, "OWNER");
        queryWrapper.eq(!(input.getOwner() == null), "OWNER", input.getOwner());
        
        queryWrapper.isNull(input.getSkuId() == null, "SKU_ID");
        queryWrapper.eq(!(input.getSkuId() == null), "SKU_ID", input.getSkuId());
        
        queryWrapper.isNull(input.getFactory() == null, "FACTORY");
        queryWrapper.eq(!(input.getFactory() == null), "FACTORY", input.getFactory());

        queryWrapper.isNull(input.getVendorId() == null, "VENDOR_ID");
        queryWrapper.eq(!(input.getVendorId() == null), "VENDOR_ID", input.getVendorId());

        queryWrapper.isNull(input.getLotNo() == null, "LOTNO");
        queryWrapper.eq(!(input.getLotNo() == null), "LOTNO", input.getLotNo());

        queryWrapper.isNull(input.getInvAttr() == null, "INV_ATTR");
        queryWrapper.eq(!(input.getInvAttr() == null), "INV_ATTR", input.getInvAttr());

        queryWrapper.isNull(input.getQaStatus() == null, "QA_STATUS");
        queryWrapper.eq(!(input.getQaStatus() == null), "QA_STATUS", input.getQaStatus());

        List<InvZone> list = invZoneMapper.selectList(queryWrapper);
        return list;
    }
    
    /**
     * 添加日志事务!
     *
     * @param input
     * @return 
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer insertInvTrans(InvTrans input) {
    	invTransMapper.insert(input);
    	return input.getInvTransId();
    }
    
    /*..............................................................................................*/
    
    /**
     * 检验可用库存，【其他出库】专用
     * 
     * @param input
     * @param qty
     * @return
     */
    public void otherStockOutValidation(InventoryConditionDto input, BigDecimal qty) {
    	QueryWrapper<InvLoc> queryWrapper = new QueryWrapper<>();
        queryWrapper.isNull(input.getLocId() == null, "LOC_ID");
        queryWrapper.eq(!(input.getLocId() == null), "LOC_ID", input.getLocId());
        
        queryWrapper.isNull(input.getWhsId() == null, "WHS_ID");
        queryWrapper.eq(!(input.getWhsId() == null), "WHS_ID", input.getWhsId());
        
        queryWrapper.isNull(input.getOwner() == null, "OWNER");
        queryWrapper.eq(!(input.getOwner() == null), "OWNER", input.getOwner());
        
        queryWrapper.isNull(input.getSkuId() == null, "SKU_ID");
        queryWrapper.eq(!(input.getSkuId() == null), "SKU_ID", input.getSkuId());
        
        queryWrapper.isNull(input.getFactory() == null, "FACTORY");
        queryWrapper.eq(!(input.getFactory() == null), "FACTORY", input.getFactory());

        queryWrapper.isNull(input.getVendorId() == null, "VENDOR_ID");
        queryWrapper.eq(!(input.getVendorId() == null), "VENDOR_ID", input.getVendorId());

        queryWrapper.isNull(input.getLotNo() == null, "LOTNO");
        queryWrapper.eq(!(input.getLotNo() == null), "LOTNO", input.getLotNo());

        queryWrapper.isNull(input.getInvAttr() == null, "INV_ATTR");
        queryWrapper.eq(!(input.getInvAttr() == null), "INV_ATTR", input.getInvAttr());

        // 添加非空校验
        queryWrapper.isNull(input.getQaStatus() == null, "QA_STATUS");

        List<InvLoc> list = invLocMapper.selectList(queryWrapper);
        if (list.size() > 0) {
        	// 数量-预支-冻结-分配
        	BigDecimal invQty = list.stream().map(t -> t.getQty().subtract(t.getPreOutQty()).subtract(t.getHoldQty())
        			.subtract(t.getAlocQty())).reduce(BigDecimal.ZERO, BigDecimal::add);
        	if (invQty.compareTo(qty) == -1) {
        		Shift.fatal("可用库存不足，需求[" + qty + "]，可用库存[" + invQty + "]");
        	}
        } else {
        	Shift.fatal("可用库存不足，需求[" + qty + "]，可用库存[0]");
        }
    }
    
    /**
     * 获取可用库存，【一键调拨】专用
     *
     * @param input
     * @return
     */
    public BigDecimal getSingleStepTransferInvQty(InventoryConditionDto input) {
        QueryWrapper<InvZone> queryWrapper = new QueryWrapper<>();
        
        queryWrapper.isNull(input.getWhsId() == null, "WHS_ID");
        queryWrapper.eq(!(input.getWhsId() == null), "WHS_ID", input.getWhsId());
        
        queryWrapper.isNull(input.getOwner() == null, "OWNER");
        queryWrapper.eq(!(input.getOwner() == null), "OWNER", input.getOwner());
        
        queryWrapper.isNull(input.getSkuId() == null, "SKU_ID");
        queryWrapper.eq(!(input.getSkuId() == null), "SKU_ID", input.getSkuId());
        
        queryWrapper.isNull(input.getFactory() == null, "FACTORY");
        queryWrapper.eq(!(input.getFactory() == null), "FACTORY", input.getFactory());

        queryWrapper.isNull(input.getVendorId() == null, "VENDOR_ID");
        queryWrapper.eq(!(input.getVendorId() == null), "VENDOR_ID", input.getVendorId());

        queryWrapper.isNull(input.getLotNo() == null, "LOTNO");
        queryWrapper.eq(!(input.getLotNo() == null), "LOTNO", input.getLotNo());

        queryWrapper.isNull(input.getInvAttr() == null, "INV_ATTR");
        queryWrapper.eq(!(input.getInvAttr() == null), "INV_ATTR", input.getInvAttr());

        // 添加非空校验，不知对程序有没印象
        queryWrapper.eq(!(input.getQaStatus() == null), "QA_STATUS", input.getQaStatus());
        
        List<InvZone> list = invZoneMapper.selectList(queryWrapper);
        if (list.size() == 0) {
        	return BigDecimal.ZERO;
        } else {
        	// 数量-预支-冻结-分配
        	BigDecimal invQty = list.stream().map(t -> t.getQty().subtract(t.getPreOutQty()).subtract(t.getHoldQty())
        			.subtract(t.getAlocQty())).reduce(BigDecimal.ZERO, BigDecimal::add);
        	return invQty;
        }
    }





    //更新库位库存【废弃】
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer updateLocCountQty(UpdateInventoryInputDto input) throws Exception {
        // 仓库、库位、货主、物料、组织、供应商、批次号、库存性质、品质状态
        String key = "Key_Inv_Loc_"
                + input.getWhsId() + "#loc" + input.getLocId() + "#" + input.getOwner() + "#"
                + input.getSkuId() + "#" + input.getFactory() + "#" + input.getVendorId() + "#"
                + input.getLotNo() + "#" + input.getInvAttr() + "#" + input.getQaStatus() + "#";
        RLock lock = redisson.getLock(key);
        try {
            // 加锁
            long waitTime = LockNumber.SECONDS_I;	// 等待时间
            long leaseTime = LockNumber.SECONDS_II;	// 过期时间
            if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
                if(StringUtils.isNull(input.getOperator())) {
                    // 默认用户名
                    input.setOperator(CommonString.DEFAULT_USER_NAME);
                }
                List<InvLoc> invLocList = getOrAddLocInvItem(input);
                Integer invLocId = invLocList.get(0).getInvLocId();
                // 库位库存检验
                invQtyValidation(input, 0);
                invLocMapper.updateCuntLoc(
                        invLocId,
                        input.getQty(),
                        input.getOperator());
                return invLocId;
            } else {
                Shift.fatal("获取库存锁失败，库存更新失败！");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            // 当前线程获取到锁再释放锁
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return null;
    }

    /**
     * 更新库区库存【废弃】
     *
     * @param input
     * @return
     * @return
     * @throws Exception
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Integer updateZoneCountQty(UpdateInventoryInputDto input) throws Exception {
        // 根据库位获取库区【库位不为空并且库区为空时触发】
        if (input.getLocId() != null && input.getZoneId() == null) {
            Location location = locationMapper.selectById(input.getLocId());
            input.setZoneId(location.getZoneId());
        }

        // 仓库、库区、货主、物料、组织、供应商、批次号、库存性质、品质状态
        String key = "Key_Inv_Zone_"
                + input.getWhsId() + "#zone" + input.getZoneId() + "#" + input.getOwner() + "#"
                + input.getSkuId() + "#" + input.getFactory() + "#" + input.getVendorId() + "#"
                + input.getLotNo() + "#" + input.getInvAttr() + "#" + input.getQaStatus() + "#";
        RLock lock = redisson.getLock(key);
        try {
            // 加锁
            long waitTime = LockNumber.SECONDS_I;	// 等待时间
            long leaseTime = LockNumber.SECONDS_II;	// 过期时间
            if (lock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS)) {
                if(StringUtils.isNull(input.getOperator())) {
                    // 默认用户名
                    input.setOperator(CommonString.DEFAULT_USER_NAME);
                }
                List<InvZone> invZoneList = getOrAddZoneItem(input);
                Integer invZoneId = invZoneList.get(0).getInvZoneId();
                // 库区库存检验
                invQtyValidation(input, 1);
                invZoneMapper.updateCuntLocZone(
                        invZoneId,
                        input.getQty(),
                        input.getOperator());
                return invZoneId;
            } else {
                Shift.fatal("获取库存锁失败，库存更新失败！");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            // 当前线程获取到锁再释放锁
            if (lock != null && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
        return null;
    }

}